/* Copyright (C) 2010 Luca Piccinelli
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "generators/resource/CvImgDirectoryGenerator.h"
#include "factory/ResourceGeneratorFactory.h"

#include <string>

#include <cv.h>
#include <highgui.h>

#include <boost/filesystem.hpp>

using namespace std;
using namespace cv;
using namespace boost::filesystem;

namespace NAMESPACE {

// ****** AbstractDirectoryGenerator implementation ****************************

//  _____________________________________________________
// |   Private functions                                 |
// |_____________________________________________________|

void CvImgDirectoryGenerator::free_element(IOElement* el){
    cv::Mat* frame = boost::any_cast<cv::Mat*>( el->getElement() );
    delete frame;
}

memory_size_t CvImgDirectoryGenerator::measure_memory(){
    if(!generated_buffer->size()) return 0;

    std::vector<IOElement*>::const_iterator it = generated_buffer->begin();
    memory_size_t mem = 0;
    cv::Mat* tmp_m;
    for(; it != generated_buffer->end(); it++){
        tmp_m = boost::any_cast<cv::Mat*>((*it)->getElement());
        mem += tmp_m->rows * tmp_m->cols * tmp_m->channels() * sizeof(char);
    }

    return mem;
}

// .......................................................

//  _____________________________________________________
// |   Standard constructors                             |
// |_____________________________________________________|

CvImgDirectoryGenerator::~CvImgDirectoryGenerator(){
    free_buffer();
}
CvImgDirectoryGenerator::CvImgDirectoryGenerator() : AbstractDirectoryGenerator(){
    key->setType(TypeParseTraits<cv::Mat*>::name());
}
CvImgDirectoryGenerator::CvImgDirectoryGenerator(const CvImgDirectoryGenerator& g)
                                                 : AbstractDirectoryGenerator(g){
    key->setType(TypeParseTraits<cv::Mat*>::name());
}
CvImgDirectoryGenerator& CvImgDirectoryGenerator::operator=(const CvImgDirectoryGenerator& g){
    if(this == &g) return *this;

    AbstractDirectoryGenerator::operator =(g);

    return *this;
}
// .......................................................

//  _____________________________________________________
// |   Others constructors                               |
// |_____________________________________________________|

CvImgDirectoryGenerator::CvImgDirectoryGenerator(const std::string& _resource,
                                                 const memory_size_t& _max_mem)
                                                 : AbstractDirectoryGenerator(_resource, _max_mem){}
CvImgDirectoryGenerator::CvImgDirectoryGenerator(const IOKey& k,
                                                 const memory_size_t& _max_mem )
                                                 : AbstractDirectoryGenerator(k, _max_mem){
    key->setType(TypeParseTraits<cv::Mat*>::name());
}
CvImgDirectoryGenerator::CvImgDirectoryGenerator(const std::string& _resource,
                                                 const IOKey& k,
                                                 const memory_size_t& _max_mem)
                                                 : AbstractDirectoryGenerator(_resource, k, _max_mem){
    key->setType(TypeParseTraits<cv::Mat*>::name());
}
// .......................................................

Generator& CvImgDirectoryGenerator::set_key(const std::string& ns, const std::string& key_name){
    AbstractGenerator::set_key(ns, key_name);
    key->setType(TypeParseTraits<cv::Mat*>::name());
    return *this;
}

IOElement* CvImgDirectoryGenerator::generate(const IOKey& key){
    if(!is_open) return 0;

    cv::Mat* frame = new cv::Mat();
    string file_name;
    while(frame->data == NULL && is_open){
        file_name = next_element();
        *frame = imread(file_name, -1);
    }
    IOElement* el = new HandledIOElement(frame, key);

    return el;
}

// -----------------------------------------------------------------------------

REGISTER_PARSE_TYPE(CvImgDirectoryGenerator);
ResourceGeneratorFactory<CvImgDirectoryGenerator> cvImgDirectoryGenerator_instance;
}